#ifndef __FMT_H__
#define __FMT_H__
#include <vector>
#include <sstream>
#include <cassert>
#include "util.hpp"
#include "level.hpp"
#include "message.hpp"

namespace nanlog {
    // 抽象格式化子项基类
    class FormatItem {
    public: 
        using ptr = std::shared_ptr<FormatItem>;
        virtual void format(std::ostream &out, const LogMsg &msg) = 0;
    };

    // 派生格式化子项子类 -- 消息 等级 时间 文件名 行号 线程ID 日志器名 制表符 换行 其他
    class MsgFormatItem : public FormatItem {
    public:
        virtual void format(std::ostream &out, const LogMsg &msg) override {
            out << msg._payload;
        }
    };

    class LevelFormatItem : public FormatItem {
    public:
        virtual void format(std::ostream &out, const LogMsg &msg) override {
            out << LogLevel::toString(msg._level);
        }
    };

    class TimeFormatItem : public FormatItem {
    public:
        TimeFormatItem(const std::string &fmt = "%H:%M:%S") : _time_fmt(fmt) {};
        virtual void format(std::ostream &out, const LogMsg &msg) override {
            struct tm t;
            localtime_r(&msg._ctime, &t);
            char tmp[32] = {0};
            strftime(tmp, 31, _time_fmt.c_str(), &t);
            out << tmp;
        }
    private: 
        std::string _time_fmt; // %H:%M:%S
    };


    class FileFormatItem : public FormatItem {
    public:
        virtual void format(std::ostream &out, const LogMsg &msg) override {
            out << msg._file;
        }
    };

    class LineFormatItem : public FormatItem {
    public:
        virtual void format(std::ostream &out, const LogMsg &msg) override {
            out << msg._line;
        }
    };

    class ThreadFormatItem : public FormatItem {
    public:
        virtual void format(std::ostream &out, const LogMsg &msg) override {
            out << msg._tid;
        }
    };

    class LoggerFormatItem : public FormatItem {
    public:
        void format(std::ostream &out, const LogMsg &msg) override {
            out << msg._logger;
        }
    };

    class TabFormatItem : public FormatItem {
    public:
        void format(std::ostream &out, const LogMsg &msg) override {
            out << '\t';
        }
    };

    class NewLineFormatItem : public FormatItem {
    public:
        void format(std::ostream &out, const LogMsg &msg) override {
            out << '\n';
        }
    };

    class OtherFormatItem : public FormatItem {
    public:
        OtherFormatItem(const std::string &str) :_str(str){}
        void format(std::ostream &out, const LogMsg &msg) override {
            out << _str;
        }
    private:
        std::string _str;
    };

    /* 
        %d  表示日期，    子格式 {%H:%M:%S}  %d{%H:%M:%S}
        %t  表示鲜橙ID 
        %c  表示日志器名称
        %f  表示源码文件名
        %l  表示源码行号
        %p  表示日志级别
        %T  表示制表符缩进
        %m  表示主体消息
        %n  表示换行
    */
    class Formatter {
        public:
            using ptr = std::shared_ptr<Formatter>;
            Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n"):
                _pattern(pattern) {
                    assert(parsePattern());
                }
            /*  对msg进行格式化--重载*/
            std::string format(const LogMsg &msg) {
                std::stringstream ss;
                format(ss, msg);
                return ss.str();
            }
            void format(std::ostream &out, const LogMsg &msg) {
                for (auto &item : _items) {
                    item->format(out, msg);
                }
            }
            /* 对格式化字符串进行解析 */
            bool parsePattern() {
                // 1、对格式化规则字符串进行解析
                std::vector<std::pair<std::string, std::string>> fmt_order;
                size_t pos = 0;
                std::string key, val;
                while (pos < _pattern.size()) {
                    // (一) 处理原始字符串 -- 判断是否为%，不是就是原始字符串
                    if (_pattern[pos] != '%') {
                        val.push_back(_pattern[pos++]); continue;
                    }
                    if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '%') {
                        val.push_back('%'); pos += 2; continue;
                    }
                    // 万一出现第一个自符就是格式化字符串，那么处理原始字符串的操作就会向数组插入{"",""}
                    // 虽然不会产生错误但是便于逻辑理解，最好还是判断处理一下
                    if (!val.empty()) {
                        fmt_order.push_back(std::make_pair("", val));
                    }
                    val.clear();

                    // (二) 处理格式化字符串,代表原始字符串处理完毕
                    pos += 1;
                    if (pos == _pattern.size()) { 
                        std::cout << "%之后没有对应的格式化字符" << std::endl;
                        return false; 
                    }
                    key = _pattern[pos];
                    pos += 1;
                    // 此时pos指向格式化字符串后面的位置，判断是否有格式化子串
                    if (pos < _pattern.size() && _pattern[pos] == '{') {
                        pos += 1;   
                        // 这时pos指向子规则的起始位置
                        while (pos < _pattern.size() && _pattern[pos] != '}') {
                            val.push_back(_pattern[pos++]);
                        }
                        // 若走到了末尾，还没有找到},则说明格式是错误的，跳出循环
                        if (pos == _pattern.size()) {   
                            std::cout << "子规则{}匹配出错" << std::endl;
                            return false;
                        }
                        pos += 1; // 因为pos指向的是 } 位置，向后走一步就到了下一次处理的新位置
                    }
                    fmt_order.push_back(std::make_pair(key, val));
                    key.clear(); val.clear();
                }
                // 2、根据解析得到的数据初始化格式子项数组成员
                for (auto &it : fmt_order) {
                    _items.push_back(createItem(it.first, it.second));
                } 
                return true;
            }
        private:
            /* 根据不同的格式化字符创建不同的格式化子项对象 */
            FormatItem::ptr createItem(const std::string &key, const::std::string &val) {
                if (key == "d")  return std::make_shared<TimeFormatItem>(val);
                if (key == "t")  return std::make_shared<ThreadFormatItem>();
                if (key == "c")  return std::make_shared<LoggerFormatItem>();
                if (key == "f")  return std::make_shared<FileFormatItem>();
                if (key == "l")  return std::make_shared<LineFormatItem>();
                if (key == "p")  return std::make_shared<LevelFormatItem>();
                if (key == "T")  return std::make_shared<TabFormatItem>();
                if (key == "m")  return std::make_shared<MsgFormatItem>();
                if (key == "n")  return std::make_shared<NewLineFormatItem>();
                if (key.empty()) return std::make_shared<OtherFormatItem>(val);
                std::cout << "没有对应的格式化字符: %" << key <<std::endl;
                assert(false);   return FormatItem::ptr();
            }
        private:
            std::string _pattern;
            std::vector<FormatItem::ptr> _items;
    };
}

#endif
